﻿// Copyright (c) Pomelo Foundation. All rights reserved.
// Licensed under the MIT. See LICENSE in the project root for license information.

using System;
using System.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.EntityFrameworkCore.Update;

namespace Pomelo.EntityFrameworkCore.MySql.Update.Internal;

public class MySqlModificationCommand : ModificationCommand
{
    private readonly bool _detailedErrorsEnabled;

    public MySqlModificationCommand(in ModificationCommandParameters modificationCommandParameters)
        : base(in modificationCommandParameters)
        => _detailedErrorsEnabled = modificationCommandParameters.DetailedErrorsEnabled;

    public MySqlModificationCommand(in NonTrackedModificationCommandParameters modificationCommandParameters)
        : base(in modificationCommandParameters)
    {
    }

    public override void PropagateResults(RelationalDataReader relationalReader)
    {
        // The default implementation of PropagateResults skips (output) parameters, since for e.g. SQL Server these aren't yet populated
        // when consuming the result set (propagating output columns is done later, after the reader is closed).
        // However, in MySQL, output parameters actually get returned as the result set, so we override and take care of that here.
        var columnCount = ColumnModifications.Count;

        var readerIndex = -1;

        for (var columnIndex = 0; columnIndex < columnCount; columnIndex++)
        {
            var columnModification = ColumnModifications[columnIndex];

            switch (columnModification.Column)
            {
                case IColumn when columnModification.IsRead:
                case IStoreStoredProcedureParameter { Direction: ParameterDirection.Output or ParameterDirection.InputOutput }:
                    readerIndex++;
                    break;

                case IColumn:
                case IStoreStoredProcedureParameter:
                case null when columnModification.JsonPath is not null:
                    continue;

                default:
                    throw new ArgumentOutOfRangeException();
            }

            // For regular result sets, results are always propagated back into entity properties.
            // But with stored procedures, there may be a rows affected result column (generated by an output parameter definition).
            // Skip these.
            if (columnModification.Property is null ||
                !columnModification.IsRead)
            {
                continue;
            }

            columnModification.Value =
                columnModification.Property.GetReaderFieldValue(relationalReader, readerIndex, _detailedErrorsEnabled);
        }
    }
}
